#include "core/database_manager.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>

// 全局数据库管理器实例
std::unique_ptr<DatabaseManager> g_databaseManager;

// ==================== MySQL连接池实现 ====================

MySQLConnectionPool::MySQLConnectionPool(const DatabaseConfig& cfg) 
    : config(cfg), initialized(false) {
}

MySQLConnectionPool::~MySQLConnectionPool() {
    cleanup();
}

bool MySQLConnectionPool::initialize() {
    std::lock_guard<std::mutex> lock(mutex);
    
    if (initialized) {
        return true;
    }
    
    // 初始化MySQL库
    if (mysql_library_init(0, nullptr, nullptr) != 0) {
        std::cerr << "Failed to initialize MySQL library" << std::endl;
        return false;
    }
    
    // 创建初始连接
    for (int i = 0; i < config.pool_size; ++i) {
        MYSQL* conn = createConnection();
        if (conn) {
            connections.push(conn);
        } else {
            std::cerr << "Failed to create initial connection " << i << std::endl;
            cleanup();
            return false;
        }
    }
    
    initialized = true;
    std::cout << "MySQL connection pool initialized with " << connections.size() << " connections" << std::endl;
    return true;
}

void MySQLConnectionPool::cleanup() {
    std::lock_guard<std::mutex> lock(mutex);
    
    while (!connections.empty()) {
        MYSQL* conn = connections.front();
        connections.pop();
        mysql_close(conn);
    }
    
    mysql_library_end();
    initialized = false;
}

MYSQL* MySQLConnectionPool::getConnection() {
    std::unique_lock<std::mutex> lock(mutex);
    
    // 等待可用连接
    condition.wait(lock, [this] { return !connections.empty() || !initialized; });
    
    if (!initialized || connections.empty()) {
        return nullptr;
    }
    
    MYSQL* conn = connections.front();
    connections.pop();
    
    // 检查连接是否有效
    if (!isConnectionValid(conn)) {
        mysql_close(conn);
        conn = createConnection();
    }
    
    return conn;
}

void MySQLConnectionPool::releaseConnection(MYSQL* conn) {
    if (!conn) return;
    
    std::lock_guard<std::mutex> lock(mutex);
    connections.push(conn);
    condition.notify_one();
}

MYSQL* MySQLConnectionPool::createConnection() {
    MYSQL* conn = mysql_init(nullptr);
    if (!conn) {
        std::cerr << "Failed to initialize MySQL connection" << std::endl;
        return nullptr;
    }
    
    // 设置连接选项
    unsigned int timeout = config.timeout;
    mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
    mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout);
    mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout);
    
    // 启用自动重连
    bool reconnect = true;
    mysql_options(conn, MYSQL_OPT_RECONNECT, &reconnect);
    
    // 连接到数据库
    if (!mysql_real_connect(conn, 
                           config.host.c_str(),
                           config.username.c_str(),
                           config.password.c_str(),
                           config.database.c_str(),
                           config.port,
                           nullptr, 
                           CLIENT_MULTI_STATEMENTS)) {
        std::cerr << "Failed to connect to MySQL: " << mysql_error(conn) << std::endl;
        mysql_close(conn);
        return nullptr;
    }
    
    // 设置字符集
    if (mysql_set_character_set(conn, "utf8mb4") != 0) {
        std::cerr << "Failed to set character set: " << mysql_error(conn) << std::endl;
    }
    
    return conn;
}

bool MySQLConnectionPool::isConnectionValid(MYSQL* conn) {
    if (!conn) return false;
    
    // 执行简单查询检查连接
    if (mysql_ping(conn) != 0) {
        return false;
    }
    
    return true;
}

// ==================== MySQL连接管理器实现 ====================

MySQLConnection::MySQLConnection(MySQLConnectionPool* p) : pool(p) {
    connection = pool ? pool->getConnection() : nullptr;
}

MySQLConnection::~MySQLConnection() {
    if (connection && pool) {
        pool->releaseConnection(connection);
    }
}

// ==================== 数据库管理器实现 ====================

DatabaseManager::DatabaseManager(const DatabaseConfig& cfg) : config(cfg) {
    connectionPool = std::make_unique<MySQLConnectionPool>(config);
}

DatabaseManager::~DatabaseManager() {
    cleanup();
}

bool DatabaseManager::initialize() {
    return connectionPool->initialize();
}

void DatabaseManager::cleanup() {
    if (connectionPool) {
        connectionPool->cleanup();
    }
}

// ==================== 用户管理 ====================

bool DatabaseManager::insertUser(const std::shared_ptr<UserInfo>& user) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "INSERT INTO users (user_id, nickname, status, ip_address, login_time, last_active_time) "
                       "VALUES ('" + escapeString(user->userId) + "', "
                       "'" + escapeString(user->nickname) + "', "
                       + std::to_string(static_cast<int>(user->status)) + ", "
                       "'" + escapeString(user->ip) + "', "
                       "FROM_UNIXTIME(" + std::to_string(user->loginTime) + "), "
                       "FROM_UNIXTIME(" + std::to_string(user->lastActiveTime) + "))";
    
    return executeQuery(conn.get(), query);
}

bool DatabaseManager::updateUser(const std::shared_ptr<UserInfo>& user) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "UPDATE users SET "
                       "nickname = '" + escapeString(user->nickname) + "', "
                       "status = " + std::to_string(static_cast<int>(user->status)) + ", "
                       "ip_address = '" + escapeString(user->ip) + "', "
                       "last_active_time = FROM_UNIXTIME(" + std::to_string(user->lastActiveTime) + ") "
                       "WHERE user_id = '" + escapeString(user->userId) + "'";
    
    return executeQuery(conn.get(), query);
}

bool DatabaseManager::deleteUser(const std::string& userId) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "DELETE FROM users WHERE user_id = '" + escapeString(userId) + "'";
    return executeQuery(conn.get(), query);
}

std::shared_ptr<UserInfo> DatabaseManager::getUser(const std::string& userId) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return nullptr;
    
    std::string query = "SELECT user_id, nickname, status, ip_address, "
                       "UNIX_TIMESTAMP(login_time) as login_time, "
                       "UNIX_TIMESTAMP(last_active_time) as last_active_time "
                       "FROM users WHERE user_id = '" + escapeString(userId) + "'";
    
    MYSQL_RES* result = executeSelect(conn.get(), query);
    if (!result) return nullptr;
    
    std::shared_ptr<UserInfo> user = resultToUser(result);
    mysql_free_result(result);
    
    if (user) {
        // 加载用户的私聊列表
        user->privateChats = std::unordered_set<std::string>(getUserPrivateChats(userId).begin(), getUserPrivateChats(userId).end());
        
        // 加载用户的群组列表
        auto groups = getUserGroups(userId);
        for (const auto& group : groups) {
            user->groups.insert(group->groupId);
        }
    }
    
    return user;
}

std::vector<std::shared_ptr<UserInfo>> DatabaseManager::getOnlineUsers() {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return {};
    
    std::string query = "SELECT user_id, nickname, status, ip_address, "
                       "UNIX_TIMESTAMP(login_time) as login_time, "
                       "UNIX_TIMESTAMP(last_active_time) as last_active_time "
                       "FROM users WHERE status = " + std::to_string(STATUS_ONLINE);
    
    MYSQL_RES* result = executeSelect(conn.get(), query);
    if (!result) return {};
    
    std::vector<std::shared_ptr<UserInfo>> users;
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result))) {
        if (row[0] && row[1]) {
            auto user = std::make_shared<UserInfo>(row[0], 0, row[3] ? row[3] : "");
            user->nickname = row[1];
            user->status = static_cast<UserStatus>(std::stoi(row[2]));
            user->loginTime = row[4] ? std::stoll(row[4]) : 0;
            user->lastActiveTime = row[5] ? std::stoll(row[5]) : 0;
            users.push_back(user);
        }
    }
    
    mysql_free_result(result);
    return users;
}

bool DatabaseManager::updateUserStatus(const std::string& userId, UserStatus status) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "UPDATE users SET status = " + std::to_string(static_cast<int>(status)) + 
                       " WHERE user_id = '" + escapeString(userId) + "'";
    
    return executeQuery(conn.get(), query);
}

bool DatabaseManager::updateUserActivity(const std::string& userId) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "UPDATE users SET last_active_time = NOW() "
                       "WHERE user_id = '" + escapeString(userId) + "'";
    
    return executeQuery(conn.get(), query);
}

// ==================== 私聊管理 ====================

bool DatabaseManager::insertPrivateChat(const std::shared_ptr<PrivateChat>& chat) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "INSERT INTO private_chats (chat_id, user1_id, user2_id, create_time, last_active_time) "
                       "VALUES ('" + escapeString(chat->chatId) + "', "
                       "'" + escapeString(chat->user1) + "', "
                       "'" + escapeString(chat->user2) + "', "
                       "FROM_UNIXTIME(" + std::to_string(chat->createTime) + "), "
                       "FROM_UNIXTIME(" + std::to_string(chat->lastActiveTime) + "))";
    
    return executeQuery(conn.get(), query);
}

bool DatabaseManager::updatePrivateChatActivity(const std::string& chatId) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "UPDATE private_chats SET last_active_time = NOW() "
                       "WHERE chat_id = '" + escapeString(chatId) + "'";
    
    return executeQuery(conn.get(), query);
}

std::shared_ptr<PrivateChat> DatabaseManager::getPrivateChat(const std::string& chatId) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return nullptr;
    
    std::string query = "SELECT chat_id, user1_id, user2_id, "
                       "UNIX_TIMESTAMP(create_time) as create_time, "
                       "UNIX_TIMESTAMP(last_active_time) as last_active_time "
                       "FROM private_chats WHERE chat_id = '" + escapeString(chatId) + "'";
    
    MYSQL_RES* result = executeSelect(conn.get(), query);
    if (!result) return nullptr;
    
    std::shared_ptr<PrivateChat> chat = resultToPrivateChat(result);
    mysql_free_result(result);
    
    return chat;
}

std::vector<std::string> DatabaseManager::getUserPrivateChats(const std::string& userId) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return {};
    
    std::string query = "SELECT chat_id FROM user_private_chats WHERE user_id = '" + escapeString(userId) + "'";
    
    MYSQL_RES* result = executeSelect(conn.get(), query);
    if (!result) return {};
    
    std::vector<std::string> chats;
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result))) {
        if (row[0]) {
            chats.push_back(row[0]);
        }
    }
    
    mysql_free_result(result);
    return chats;
}

// ==================== 消息管理 ====================

bool DatabaseManager::insertMessage(const EnhancedMessage& message) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return false;
    
    std::string query = "INSERT INTO messages (message_id, message_type, from_user_id, to_user_id, group_id, content, chat_type, created_at) "
                       "VALUES ('" + escapeString(message.messageId) + "', "
                       + std::to_string(static_cast<int>(message.type)) + ", "
                       "'" + escapeString(message.fromUser) + "', ";
    
    if (!message.toUser.empty()) {
        query += "'" + escapeString(message.toUser) + "', ";
    } else {
        query += "NULL, ";
    }
    
    if (!message.groupId.empty()) {
        query += "'" + escapeString(message.groupId) + "', ";
    } else {
        query += "NULL, ";
    }
    
    query += "'" + escapeString(message.content) + "', "
           + std::to_string(static_cast<int>(message.chatType)) + ", "
           "FROM_UNIXTIME(" + std::to_string(message.timestamp) + "))";
    
    return executeQuery(conn.get(), query);
}

std::vector<EnhancedMessage> DatabaseManager::getPrivateMessages(const std::string& user1, const std::string& user2, int limit, int offset) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return {};
    
    std::string query = "SELECT message_id, message_type, from_user_id, to_user_id, group_id, content, chat_type, "
                       "UNIX_TIMESTAMP(created_at) as timestamp "
                       "FROM messages WHERE "
                       "((from_user_id = '" + escapeString(user1) + "' AND to_user_id = '" + escapeString(user2) + "') OR "
                       "(from_user_id = '" + escapeString(user2) + "' AND to_user_id = '" + escapeString(user1) + "')) "
                       "ORDER BY created_at DESC LIMIT " + std::to_string(limit) + " OFFSET " + std::to_string(offset);
    
    MYSQL_RES* result = executeSelect(conn.get(), query);
    if (!result) return {};
    
    std::vector<EnhancedMessage> messages;
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result))) {
        messages.push_back(resultToMessage(result));
    }
    
    mysql_free_result(result);
    return messages;
}

// ==================== 工具方法 ====================

std::string DatabaseManager::escapeString(const std::string& str) {
    MySQLConnection conn(connectionPool.get());
    if (!conn) return str;
    
    char* escaped = new char[str.length() * 2 + 1];
    mysql_real_escape_string(conn.get(), escaped, str.c_str(), str.length());
    std::string result(escaped);
    delete[] escaped;
    return result;
}

std::shared_ptr<UserInfo> DatabaseManager::resultToUser(MYSQL_RES* result) {
    MYSQL_ROW row = mysql_fetch_row(result);
    if (!row || !row[0] || !row[1]) return nullptr;
    
    auto user = std::make_shared<UserInfo>(row[0], 0, row[3] ? row[3] : "");
    user->nickname = row[1];
    user->status = static_cast<UserStatus>(std::stoi(row[2]));
    user->loginTime = row[4] ? std::stoll(row[4]) : 0;
    user->lastActiveTime = row[5] ? std::stoll(row[5]) : 0;
    
    return user;
}

std::shared_ptr<PrivateChat> DatabaseManager::resultToPrivateChat(MYSQL_RES* result) {
    MYSQL_ROW row = mysql_fetch_row(result);
    if (!row || !row[0] || !row[1] || !row[2]) return nullptr;
    
    auto chat = std::make_shared<PrivateChat>(row[1], row[2]);
    chat->createTime = row[3] ? std::stoll(row[3]) : 0;
    chat->lastActiveTime = row[4] ? std::stoll(row[4]) : 0;
    
    return chat;
}

EnhancedMessage DatabaseManager::resultToMessage(MYSQL_RES* result) {
    MYSQL_ROW row = mysql_fetch_row(result);
    EnhancedMessage msg;
    
    if (row) {
        msg.messageId = row[0] ? row[0] : "";
        msg.type = static_cast<EnhancedMessageType>(row[1] ? std::stoi(row[1]) : 0);
        msg.fromUser = row[2] ? row[2] : "";
        msg.toUser = row[3] ? row[3] : "";
        msg.groupId = row[4] ? row[4] : "";
        msg.content = row[5] ? row[5] : "";
        msg.chatType = static_cast<ChatType>(row[6] ? std::stoi(row[6]) : 0);
        msg.timestamp = row[7] ? std::stoll(row[7]) : 0;
    }
    
    return msg;
}

bool DatabaseManager::executeQuery(MYSQL* conn, const std::string& query) {
    if (mysql_query(conn, query.c_str()) != 0) {
        logError(conn, "executeQuery");
        return false;
    }
    return true;
}

MYSQL_RES* DatabaseManager::executeSelect(MYSQL* conn, const std::string& query) {
    if (mysql_query(conn, query.c_str()) != 0) {
        logError(conn, "executeSelect");
        return nullptr;
    }
    return mysql_store_result(conn);
}

void DatabaseManager::logError(MYSQL* conn, const std::string& operation) {
    std::cerr << "MySQL error in " << operation << ": " << mysql_error(conn) << std::endl;
}

// ==================== 全局函数 ====================

bool initializeDatabase(const DatabaseConfig& config) {
    g_databaseManager = std::make_unique<DatabaseManager>(config);
    return g_databaseManager->initialize();
}

void cleanupDatabase() {
    if (g_databaseManager) {
        g_databaseManager->cleanup();
        g_databaseManager.reset();
    }
} 